rollout exportToDX "Export to Aole 3D"
(
	-- UI ----------------------------------------------------------
	group "Project Options" (
		edittext projectName "Project Name" text:"undefined"
		edittext projectDir "Base Project Directory" readOnly:true text:(getDir #export)
		button changeProjDir "Set Base Project Directory"
	)
	group "Mesh Options" (
		checkbox chkRenderCW "Render Face Clockwise" checked:true
		checkbox chkRenderHidden "Render Hidden Geometry" checked:false
		checkbox chkSepObjFiles "Seperate Object Files" checked:false
	)
	group "Texture Options" (
		checkbox chkCreateTextureMaps "Create Texture Maps" checked:true
		checkbox chkOverwriteMapFiles "Overwrite Map Files" checked:true
		checkbox chkRenderShadow "Render Shadow" checked:false
		--checkbox chkRenderLight "Render Lightning" checked:false
		edittext txtMapSubDir "Map Sub Directory" text:"maps"
		edittext txtMapExt "Map File Extention" text:"jpg"
		spinner spnTextureSize "Texture Size" range:[1,9999,256] type:#integer
	)
	button export "Export"
	-- Functions ---------------------------------------------------
	struct vertex( x, y, z, nx, ny, nz, tu, tv )
	struct face( a, b, c )
	
	function IsVertexEqual v1 v2 =
	(
		return ( v1.x == v2.x and v1.y == v2.y and v1.z == v2.z and
				 v1.nx == v2.nx and v1.ny == v2.ny and v1.nz == v2.nz and
				 v1.tu == v2.tu and v1.tv == v2.tv )
	)
	
	function GetMeshData mesh vertices indices =
	(
		lvind = #()
		lvcnt = 0
		bFlipFaceIndices = chkRenderCW.checked-- == FaceCCW.state --or  !chkRenderCW.checked and !FaceCCW.state
		
		for f = 1 to mesh.numfaces do
		(
			mv = getface mesh f
			mt = gettvface mesh f
			mn = meshop.getFaceRNormals mesh f
			for k = 1 to 3 do
			(
				pos = getVert mesh mv[k]
				uvw = getTVert mesh mt[k]
				append vertices ( vertex pos.x pos.y pos.z mn[k].x mn[k].y mn[k].z uvw.x uvw.y )
				lvcnt = lvcnt + 1
				append lvind lvcnt
			)
			if bFlipFaceIndices then -- reverse face indices
				append indices ( face lvcnt ( lvcnt-1 ) ( lvcnt-2 ) )
			else
				append indices ( face ( lvcnt-2 ) ( lvcnt-1 ) lvcnt )
		)
		-- optimize
		-- find duplicate vertices
		for i = lvcnt to 2 by -1 do
		(
			--ipos = finditem v v[i]
			ipos = 0
			for k = 1 to i-1 do
			(
				if IsVertexEqual vertices[i] vertices[k] then
				(
					ipos = k
					exit
				)
			)
			if ipos > 0 then
			(
				-- reduce vertices and correct indices
				lvind[i] = ipos
				deleteitem vertices i
				for k = 1 to lvcnt do
				(
					if lvind[k]>=i then
						lvind[k] = lvind[k]-1
				)
			)
		)
		
		-- unduplicate face vertices
		for mv in indices do
		(
			mv.a = lvind[mv.a]
			mv.b = lvind[mv.b]
			mv.c = lvind[mv.c]
		)
	)
	
	function IndicesToFile exfile vertices indices = 
	(
		vcnt = vertices.count
		format "vertices %\n" vcnt to:exfile
		for i = 1 to vcnt do
			format "% % % % % % % %\n" vertices[i].x vertices[i].y vertices[i].z vertices[i].nx vertices[i].ny vertices[i].nz vertices[i].tu vertices[i].tv to:exfile
		
		format "faces %\n" indices.count to:exfile
		for mv in indices do
			format "% % %\n" mv.a mv.b mv.c to:exfile
	)
	
	function ApplyUVWModifier obj =
	(
		-- must be in modify mode to use flatten operator
		if (getCommandPanelTaskMode() != #modify) do setCommandPanelTaskMode #modify
		
		with redraw off
		(
			-- check if modifier already applied
			for nMod = 1 to obj.modifiers.count do
			(
				unwrapMod = obj.modifiers[ nMod ]
				if (classof unwrapMod) == Unwrap_UVW then
				(
					--if unwrapMod.name == "Automatic Flatten UVs" then
					return false
				)
			)
			
			-- apply modifier
			local flattenAngle = 45.0
			local flattenSpacing = 0.02
			local flattenRotate = true
			local flattenFillHoles = true
			
			-- select the object to apply flatten operator
			if not obj.isSelected do
				with undo off select obj
			
			unwrapMod = unwrap_UVW()
			
			unwrapMod.setAlwaysEdit false
			unwrapMod.setMapChannel 2 -- TODO: add option
			unwrapMod.setFlattenAngle flattenAngle  -- TODO: add option
			unwrapMod.setFlattenSpacing flattenSpacing  -- TODO: add option
			unwrapMod.setFlattenNormalize true
			unwrapMod.setFlattenRotate flattenRotate  -- TODO: add option
			unwrapMod.setFlattenFillHoles flattenFillHoles  -- TODO: add option
			unwrapMod.setApplyToWholeObject true
			unwrapMod.name = "Automatic Flatten UVs"
			unwrapMod.setDebugLevel 0
			unwrapMod.setTVSubObjectMode 3
			
			-- add it to the object
			-- add directly to the object to avoid groupness
			addModifier obj unwrapMod
			
			-- & flatten things
			unwrapMod.flattenMapByMatID \
				flattenAngle  \
				flattenSpacing  \
				true \
				2 \
				flattenRotate  \
				flattenFillHoles
		)
	)
	
	function BakeTexture obj filepathname =
	(
		if ( not chkOverwriteMapFiles.checked ) and ( doesFileExist filepathname ) then
			return false

		size = spnTextureSize.value
		-- Create a CompleteMap bake element
		cmap = CompleteMap()
		cmap.outputSzX = cmap.outputSzY = size
		cmap.fileType = filepathname
		cmap.fileName = filenameFromPath cmap.fileType
		cmap.filterOn = true --enable filtering
		cmap.shadowsOn = chkRenderShadow.checked
		--cmap.lightingOn = chkRenderLight.checked
		cmap.enabled = true --enable baking
		
		-- Add the bake element
		obj.INodeBakeProperties.removeAllBakeElements()
		obj.INodeBakeProperties.addBakeElement cmap
		obj.INodeBakeProperties.bakeEnabled = true --enabling baking
		obj.INodeBakeProperties.bakeChannel = 2 --channel to bake
		obj.INodeBakeProperties.nDilations = 1
		
		render rendertype:#bakeSelected vfb:off progressBar:true outputSize:[size,size]
		obj.INodeBakeProperties.removeAllBakeElements()
	)
	
	function CleanDir dir =
	(
		-- clean child directories
		cdir = GetDirectories( dir+"/*" )
		for d in cdir do
			CleanDir d
		-- clean this directory
		files = GetFiles( dir+"/*" )
		for f in files do
			deleteFile f
	)
	-- UI Call Handlers --------------------------------------------
	on changeProjDir pressed do
	(
		lDirPath = GetSavePath caption: "Project Base Directory" initialDir: projectDir.text
		if not lDirPath==undefined then projectDir.text = lDirPath
	)
	
	on export pressed do
	(
		-----
		disableSceneRedraw()
		--undo off
		(
		-----
			projDir = projectDir.text+"\\"+projectName.text
			mapDir = projDir + "\\" + txtMapSubDir.text
			-- create project directory = Base Directory + Project Name
			makeDir projDir all:false
			makeDir mapDir all:false
			
			-- create mesh file
			exfilename = projDir+"\\"+projectName.text+".aole3d"
			exfile = createfile exfilename
			format "project %\n" projectName.text to:exfile
			
			-- set camera params
			ActiveViewportIndex = viewport.activeViewport
			OrigActiveViewportType = viewport.getType()
			if OrigActiveViewportType != #view_persp_user or OrigActiveViewportType != #view_camera then
				viewport.setType #view_persp_user
			
			local coordSysTM = Inverse( getViewTM() )
			local viewDir = -coordSysTM.row3
			local viewFrom = coordSysTM.row4
			local viewTo = viewFrom + ( viewDir*10 )
			local viewFOV = getViewFOV()
			format "ViewFrom % % %\n" viewFrom.x viewFrom.y viewFrom.z to:exfile
			format "ViewTo % % %\n" viewTo.x viewTo.y viewTo.z to:exfile
			format "ViewFOV %\n" viewFOV to:exfile
			
			for obj in geometry do
			(
				-- render hidden geometry?
				if obj.isHidden and ( not chkRenderHidden.checked ) do continue
				
				if chkSepObjFiles.checked then
				(
					local f = obj.name+".aole3d"
					format "objfile %\n" f to:exfile
					objfilename = projDir+"\\"+f
					objfile = createfile objfilename
				) else
					objfile = exfile
				
				select obj
				format "geometry %\n" obj.name to:objfile
				if chkCreateTextureMaps.checked then
				(
					-- unwrap uvw
					ApplyUVWModifier obj
					textureName = obj.name+"_complete"+"."+txtMapExt.text
					-- bake textures
					BakeTexture obj ( mapDir+"\\"+textureName )
					format "diffusemap %\n" textureName to:objfile
				)
				
				m = snapshotasmesh obj
				lverts = #()
				lfaces = #()
				
				GetMeshData m lverts lfaces
				
				-- print the vertices/faces to file
				IndicesToFile objfile lverts lfaces
				
				delete m
				
				-- close object file if created
				if chkSepObjFiles.checked then
					close objfile
			)
			
			-- close project file
			close exfile
			-- restore original viewport
			viewport.setType OrigActiveViewportType
			
			--edit exfilename -- **** remove this ****
			DestroyDialog exportToDx -- **** remove this ****
		-----
		)
		enableSceneRedraw()
		-----
	)
	
)

CreateDialog exportToDx width:400

/*
Features
========
Plugin
------
. export all [visible?] objects ** DONE **
. export vertices in format vnt ** DONE **
. export trifaces indexing to exported vertices ** DONE **
. optimize vertices/indices ** DONE **
. Automatic unwrap
. Automatic texture size

Options
-------
* Project Name [text] ** DONE **
* Project Location [Folder] ** DONE **
* Overwrite Map Files [Yes/No] ** DONE **
  -- If not checked, new maps will not be rendered if already present.
  -- Usefull if there are no changes to existing meshes already baked.
* Clockwise Rendered Faces [Yes/No] ** DONE **
* View Settings from camera/perspective ** DONE **
  -- Before exporting set the active viewport to the camera of your choice
  -- for exporting view parameter.
  -- If active viewport does not have a camera, the view parameters will
  -- be taken from perspective view.
* Render Hidded Geometry [Yes/No] ** DONE **
* Seperate Object Files( as <object name>.aole3d ) [Yes/No] ** DONE **
* Create Texture for all objects [Yes/No] ** DONE **
  -- "Complete mapps will be baked for each object"
* Create Text File( aole3d ) [Yes/No] ** DONE **
* Zip Texture Files [Yes/No]
* Create C++ Starter Code [Yes/No]

Starter Code
------------
* for object class
* for shader class
* for texture class
* for setting up camera
* for loading objects in object class
* for attaching appropriate shader to object
* for loading textures from saved location
* for attaching textures to object
* for rendering objects

*/